package com.njuse.seecjvm.instructions.references;

import com.njuse.seecjvm.instructions.base.Index16Instruction;
import com.njuse.seecjvm.memory.jclass.Field;
import com.njuse.seecjvm.memory.jclass.InitState;
import com.njuse.seecjvm.memory.jclass.JClass;
import com.njuse.seecjvm.memory.jclass.runtimeConstantPool.RuntimeConstantPool;
import com.njuse.seecjvm.memory.jclass.runtimeConstantPool.constant.ref.ClassRef;
import com.njuse.seecjvm.memory.jclass.runtimeConstantPool.constant.ref.FieldRef;
import com.njuse.seecjvm.runtime.OperandStack;
import com.njuse.seecjvm.runtime.StackFrame;
import com.njuse.seecjvm.runtime.Vars;
import com.njuse.seecjvm.runtime.struct.JObject;

public class GETFIELD extends Index16Instruction {

    /**
     * TODO 实现这条指令
     * 其中 对应的index已经读取好了
     */
    @Override
    public void execute(StackFrame frame) {
    	
    	//step 1 :从操作栈里面获得一个对象reference
    	JObject tt=frame.getOperandStack().popObjectRef();
    	JClass targetClazz=tt.getClazz();
    	
    	//step2:从常量池通过Index获得一个field reference
    	RuntimeConstantPool runtimeConstantPool = frame.getMethod().getClazz().getRuntimeConstantPool();
    	FieldRef t=(FieldRef) runtimeConstantPool.getConstant(index);

    	Field field;
    	 try {
    		 //step3 获得field，初始化类（如果没有初始化），然后把field对应的值放入操作栈
    	
             field = t.getResolvedFieldRef();
             if (targetClazz.getInitState() == InitState.PREPARED) {
                 frame.setNextPC(frame.getNextPC() - 3);//opcode + operand = 3bytes
                 targetClazz.initClass(frame.getThread(), targetClazz);
                 return;
             }
             String descriptor = field.getDescriptor();
             int slotID = field.getSlotID();
             Vars staticVars = targetClazz.getStaticVars();
             OperandStack stack = frame.getOperandStack();
             switch (descriptor.charAt(0)) {
                 case 'Z':
                 case 'B':
                 case 'C':
                 case 'S':
                 case 'I':
                     stack.pushInt(staticVars.getInt(slotID));
                     break;
                 case 'F':
                     stack.pushFloat(staticVars.getFloat(slotID));
                     break;
                 case 'J':
                     stack.pushLong(staticVars.getLong(slotID));
                     break;
                 case 'D':
                     stack.pushDouble(staticVars.getDouble(slotID));
                     break;
                 case 'L':
                 case '[':
                     stack.pushObjectRef(staticVars.getObjectRef(slotID));
                     break;
                 default:
             }
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         }
    }
}
